﻿using System.Text;

using CodeBuilder.Core.Domain.Models;

using Tszy.Unlimited.Base.Extensions;

namespace Tszy.CodeBuilder.Features.Builders;

internal class ModelClassBuilder
{
    private const string tablePrefix = "bp_";
    public static string Execute(CodeTable table, string basenamespace)
    {
        var code = OnExecute(table, basenamespace, out string modelName);

        Build($"{modelName}.cs", code);

        return modelName;
    }

    private static void Build(string fileName, string template)
    {
        var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Templates");

        if (!Directory.Exists(dir))
            Directory.CreateDirectory(dir);

        var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Templates", fileName);

        File.WriteAllText(path, template);
    }

    private static string OnExecute(CodeTable table, string basenamespace, out string modelName)
    {
        var codeBuilder = new StringBuilder();

        var tableDescription = string.IsNullOrWhiteSpace(table.Description) ? "" : $"{table.Description}{(table.Description.EndsWith("。") ? "" : "。")}";
        var className = table.TableName
            .Replace(tablePrefix, "")
            .ToTitleCase()
            .Replace("-", "")
            .Replace("_", "");

        modelName = className;

        codeBuilder.AppendLine($"//============================================================================================");
        codeBuilder.AppendLine($"/*");
        codeBuilder.AppendLine($" * @brief {tableDescription}");
        codeBuilder.AppendLine($" * ");
        codeBuilder.AppendLine($" *********************************************************************************************/");
        codeBuilder.AppendLine($"");
        codeBuilder.AppendLine($"using FreeSql.DataAnnotations;");
        codeBuilder.AppendLine($"");
        if (string.IsNullOrWhiteSpace(basenamespace))
        {
            codeBuilder.AppendLine($"using Tszy.Unlimited.Base.Infrastructure.Domain;");
        }
        else
        {
            codeBuilder.AppendLine($"using {basenamespace};");
        }
        codeBuilder.AppendLine($"");

        if (table.Fields.Any(f => f.FieldType.Contains("timestamp")))
        {
            codeBuilder.AppendLine($"using System;");
            codeBuilder.AppendLine($"");
        }

        codeBuilder.AppendLine($"namespace CodeBuilder.Domain;");
        codeBuilder.AppendLine($"");
        codeBuilder.AppendLine($"/// <summary>");
        codeBuilder.AppendLine($"/// {tableDescription}");
        codeBuilder.AppendLine($"/// </summary>");
        codeBuilder.AppendLine($"[Table(Name = \"{table.TableName}\")]");
        codeBuilder.AppendLine($"public class {className} : AggregateRootBase");
        codeBuilder.AppendLine($"{{");

        var index = 0;
        foreach (var field in table.Fields)
        {
            if (index > 0)
                codeBuilder.AppendLine($"");

            var fieldName = field.FieldName.ToTitleCase();
            var fieldDescription = string.IsNullOrWhiteSpace(field.Description) ? "" : (field.Description.EndsWith("。") ? "" : "。");
            var fieldType = field.FieldType;

            switch (fieldType)
            {
                case "tinyint":
                case "bit":
                    fieldType = "bool";
                    break;
                case "decimal":
                    fieldType = "decimal";
                    break;
                case "date":
                case "datetime":
                case "timestamp":
                    fieldType = "DateTime";
                    break;
                case "int":
                    fieldType = "int";
                    break;
                case "bigint":
                    fieldType = "long";
                    break;
                case "varchar":
                case "text":
                case "longtext":
                    fieldType = "string";
                    break;
                default:
                    break;
            }

            codeBuilder.AppendLine($"    /// <summary>");
            codeBuilder.AppendLine($"    /// {fieldDescription}");
            codeBuilder.AppendLine($"    /// </summary>");
            codeBuilder.AppendLine($"    public {fieldType} {fieldName} {{ get; set; }}");

            index++;
        }

        codeBuilder.AppendLine($"}}");

        var code = codeBuilder.ToString();

        return code;
    }
}
